/*************************************************************************************
 *
 *  Revolution Engine
 *  Copyright (C) 2009 Felipe Apablaza
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ************************************************************************************/

//---------------------------------------------------------
//
//  File:	Property.hpp
//  Desc:	
//
//---------------------------------------------------------


#ifndef __re_property_hpp__
#define __re_property_hpp__

#include <cstddef>
#include <cassert>

namespace RevEng
{
	template<typename Type>
	class Property
	{
	public:
		class Foo
		{};

	public:
		typedef void (Foo::*Setter)(const Type& Data);
		typedef Type (Foo::*Getter)();

	private:
		Foo* m_pObject;
		Setter m_pSetter;
		Getter m_pGetter;

	public:
		Property() : m_pObject(NULL), m_pSetter(NULL), m_pGetter(NULL)
		{
		}


		Property(const Property& Other) : m_pObject(Other.m_pObject), m_pSetter(Other.m_pSetter), m_pGetter(Other.m_pGetter)
		{
		}


		Property(Foo* Obj, Setter Set, Getter Get) : m_pObject(Obj), m_pSetter(Set), m_pGetter(Get)
		{
		}

		void SetObject(Foo* Obj)
		{
			m_pObject = Obj;
		}


		void SetSetter(Setter Set)
		{
			m_pSetter = Set;
		}


		void SetGetter(Getter Get)
		{
			m_pGetter = Get;
		}


		Foo* GetObject() const
		{
			return m_pObject;
		}


		Setter GetSetter() const
		{
			return m_pSetter;
		}


		Getter GetGetter() const
		{
			return m_pGetter;
		}


		operator Type()
		{
			return (m_pObject->*m_pGetter)();
		}


		Property& operator= (const Type& Data)
		{
			(m_pObject->*m_pSetter)(Data);
			return *this;
		}
	};


	template<typename Class, typename Type>
	class TProperty : public Property<Type>
	{
	public:
		typedef void (Class::*Setter)(const Type& Data);
		typedef Type (Class::*Getter)();

	public:
		TProperty()
		{
    		Property<Type>::m_pObject = NULL;
            Property<Type>::m_pSetter = NULL;
            Property<Type>::m_pGetter = NULL;
		}


		TProperty(Class* Obj, Setter Set, Getter Get)
		{
			Property<Type>::SetObject( reinterpret_cast<typename Property<Type>::Foo*>(Obj) );
			Property<Type>::SetSetter( reinterpret_cast<typename Property<Type>::Setter>(Set) );
			Property<Type>::SetGetter( reinterpret_cast<typename Property<Type>::Getter>(Get) );
		}


		operator Type()
		{
			return (Property<Type>::m_pObject->*Property<Type>::m_pGetter)();
		}


		TProperty<Class, Type>& operator= (const Type& Data)
		{
			(Property<Type>::m_pObject->*Property<Type>::m_pSetter)(Data);
			return *this;
		}
	};



	template<typename Type>
	class RProperty
	{
	public:
		class Foo
		{};

	public:
		typedef Type (Foo::*Getter)();

	private:
		Foo* m_pObject;
		Getter m_pGetter;

	public:
		RProperty<Type>() : m_pObject(NULL), m_pGetter(NULL)
		{
		}


		RProperty<Type>(const RProperty<Type>& Other) : m_pObject(Other.m_pObject), m_pGetter(Other.m_pGetter)
		{
		}


		RProperty<Type>(Foo* Obj, Getter Get) : m_pObject(Obj), m_pGetter(Get)
		{
		}

		void SetObject(Foo* Obj)
		{
			m_pObject = Obj;
		}


		void SetGetter(Getter Get)
		{
			m_pGetter = Get;
		}


		Foo* GetObject() const
		{
			return m_pObject;
		}


		Getter GetGetter() const
		{
			return m_pGetter;
		}


		operator Type()
		{
			return (m_pObject->*m_pGetter)();
		}
	};


	template<typename Class, typename Type>
	class TRProperty : public RProperty<Type>
	{
	public:
		typedef Type (Class::*Getter)();

	public:
		TRProperty()
		{
		}


		TRProperty(Class* Obj, Getter Get)
		{
			Property<Type>::SetObject( reinterpret_cast<typename Property<Type>::Foo*>(Obj) );
			Property<Type>::SetGetter( reinterpret_cast<typename Property<Type>::Getter>(Get) );
		}


		operator Type()
		{
			return (Property<Type>::m_pObject->*Property<Type>::m_pGetter)();
		}
	};



	template<typename Type>
	class WProperty
	{
	public:
		class Foo
		{};

	public:
		typedef void (Foo::*Setter)(const Type& Data);

	private:
		Foo* m_pObject;
		Setter m_pSetter;

	public:
		WProperty<Type>() : m_pObject(NULL), m_pSetter(NULL)
		{
		}


		WProperty<Type>(const WProperty<Type>& Other) : m_pObject(Other.m_pObject), m_pSetter(Other.m_pSetter)
		{
		}


		WProperty<Type>(Foo* Obj, Setter Set) : m_pObject(Obj), m_pSetter(Set)
		{
		}

		void SetObject(Foo* Obj)
		{
			m_pObject = Obj;
		}


		void SetSetter(Setter Set)
		{
			m_pSetter = Set;
		}


		Foo* GetObject() const
		{
			return m_pObject;
		}


		Setter GetSetter() const
		{
			return m_pSetter;
		}

		WProperty& operator= (const Type& Data)
		{
			(m_pObject->*m_pSetter)(Data);
			return *this;
		}
	};


	template<typename Class, typename Type>
	class TWProperty : public WProperty<Type>
	{
	public:
		typedef void (Class::*Setter)(const Type& Data);

	public:
		TWProperty()
		{
		}


		TWProperty(Class* Obj, Setter Set)
		{
			WProperty<Type>::SetObject( reinterpret_cast<typename WProperty<Type>::Foo*>(Obj) );
			WProperty<Type>::SetSetter( reinterpret_cast<typename WProperty<Type>::Setter>(Set) );
		}


		TWProperty<Class, Type>& operator= (const Type& Data)
		{
			(WProperty<Type>::m_pObject->*WProperty<Type>::m_pSetter)(Data);
			return *this;
		}
	};
}

/*
	Macros utilitarias.
	Simplifican la implementacion de las propiedades
*/

/*
//Declara una propiedad
#define REVENG_DECL_PROPERTY(Class, Type, Name)						\
	public: RevEng::Property<Class, Type> Name;						\
	protected: virtual Type PropertyGet_##Name ();					\
	protected: virtual void PropertySet_##Name (const Type& Value);

//Inicializa una propiedad
#define REVENG_INIT_PROPERTY(Class, Type, Name)							\
	Name = RevEng::Property<Class, Type>(this, &Class::PropertyGet_##Name, &Class::PropertySet_##Name)

#define REVENG_DECL_ABSTRACT_PROPERTY(Class, Type, Name)						\
	public: RevEng::Property<Class, Type> Name;									\
	protected: virtual Type PropertyGet_##Name () = 0;							\
	protected: virtual void PropertySet_##Name (const Type& Value) = 0;

//Declara una propiedad de solo lectura
#define XE_DECL_READ_PROPERTY(Class, Type, Name)						\
	public: ExEng::ReadProperty<Class, Type> Name;						\
	protected: virtual Type PropertyGet_##Name();							

//Inicializa una propiedad de solo lectura
#define XE_INIT_READ_PROPERTY(Class, Type, Name)					\
	Name(this, &Class::PropertyGet_##Name)

//Declara una propiedad de solo escritura
#define XE_DECL_WRITE_PROPERTY(Class, Type, Name)					\
	public: ExEng::WriteProperty<Class, Type> Name;					\
	protected: virtual void PropertySet_##Name(const Type& Value);							

//Inicializa una propiedad de solo escritura
#define XE_INIT_WRITE_PROPERTY(Class, Type, Name)					\
	Name(this, &Class::PropertySet_##Name)
*/

#endif
